﻿#include "OperGraphEvent3D.h"

// APP
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppSettings.h"
#include "FITK_Kernel/FITKAppFramework/FITKRunTimeSetting.h"

// Global data
#include "FITK_Kernel/FITKCore/FITKDataRepo.h"

// Graph
#include "FITK_Component/FITKAcousticsVTKGraphAdaptor/FITKAcousticsVTKGraphObject3D.h"

// Render VTK
#include "FITK_Component/FITKRenderWindowVTK/FITKGraph3DWindowVTK.h"
#include "FITK_Component/FITKRenderWindowVTK/FITKGraphRender.h"
#include "FITK_Component/FITKRenderWindowVTK/FITKGraphObjectVTK.h"

// Graph data manager
#include "GraphDataProvider/GraphProviderManager.h"
#include "GraphDataProvider/GraphModelProvider.h"
#include "GraphDataProvider/GraphMarkProvider.h"

// Data
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsGeoCommand.h"
#include "FITK_Component/FITKAbaqusData/FITKAbaqusPart.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEASubSys.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEAAbstractJunction.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsFEFace.h"
#include "FITK_Component/FITKAcousticsModel/FITKFESubSysStructure.h"
#include "FITK_Component/FITKAcousticsModel/FITKFESubSysAcoustic.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSensors.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsAbstractLoad.h"

// GUI
#include "GUIFrame/MainWindow.h"
#include "GUIFrame/CentralWidget.h"
#include "GUIWidget/GraphArea.h"
#include "GUIWidget/PreWindow3D.h"
#include "FITK_Component/FITKWidget/FITKMdiArea.h"

// Pick
#include "PickDataProvider/GUIPickInfo.h"

namespace GUIOper
{
    Comp::FITKGraph3DWindowVTK* OperGraphEvent3D::getPreGraphWidget()
    {
        // 获取主窗口。
        GUI::MainWindow* mainWindow = FITKAPP->getGlobalData()->getMainWindowT<GUI::MainWindow>();
        if (!mainWindow)
        {
            return nullptr;
        }

        // 获取中心区域。
        GUI::CentralWidget* centralWidget = mainWindow->getCentralWidget();
        if (!centralWidget)
        {
            return nullptr;
        }

        // 获取3D区域。
        GUI::GraphArea* gArea = centralWidget->getGraphArea();
        if (!gArea)
        {
            return nullptr;
        }

        GUI::PreWindow3D* widget3D = nullptr;
        
        widget3D = gArea->getCurrentWindow<GUI::PreWindow3D>();
        if (widget3D == nullptr) {
            widget3D = dynamic_cast<GUI::PreWindow3D*>(gArea->getFirstWindow(GUI::GraphAbstractSubWin::SubWinType::Pre3D));
            if (widget3D == nullptr){
                return nullptr;
            }
        }

        //获取3D可视化区域
        Comp::FITKGraph3DWindowVTK* graphWidget = widget3D->getRenderWindow();
        if (!graphWidget)
        {
            return nullptr;
        }

        return graphWidget;
    }

    QList<Comp::FITKGraph3DWindowVTK*> OperGraphEvent3D::getAllGraphWidget()
    {
        QList<Comp::FITKGraph3DWindowVTK*> allGraphWidget = {};
        // 获取主窗口。
        GUI::MainWindow* mainWindow = FITKAPP->getGlobalData()->getMainWindowT<GUI::MainWindow>();
        if (mainWindow == nullptr){
            return allGraphWidget;
        }

        // 获取中心区域。
        GUI::CentralWidget* centralWidget = mainWindow->getCentralWidget();
        if (centralWidget == nullptr){
            return allGraphWidget;
        }

        // 获取3D区域。
        GUI::GraphArea* gArea = centralWidget->getGraphArea();
        if (gArea == nullptr){
            return allGraphWidget;
        }

        QList<GUI::GraphAbstractSubWin*> subWins = gArea->getSubWindowsByType(GUI::GraphAbstractSubWin::Pre3D);
        for (GUI::GraphAbstractSubWin* win : subWins) {
            GUI::PreWindow3D* Win3d = dynamic_cast<GUI::PreWindow3D*>(win);
            if (Win3d == nullptr) {
                continue;
            }
            allGraphWidget.append(Win3d->getRenderWindow());
        }
        return allGraphWidget;
    }

    void OperGraphEvent3D::addGraphObjectToWidget(Exchange::FITKAcousticsVTKGraphObject3D* obj, Comp::FITKGraph3DWindowVTK* graphWidget, bool fitView)
    {
        if (!obj || !graphWidget)
        {
            return;
        }

        // 添加可视化对象。
        //@{
        obj->removeFromGraphWidget();
        graphWidget->addObject(obj->getRenderLayer(), obj, true);
        obj->setFITKRender(graphWidget->getRenderer(obj->getRenderLayer()));
        //}

        // 添加附加可视化对象。
        //@{
        QList<Exchange::FITKAcousticsVTKGraphObject3D*> addinObjs = obj->getAddinGraphObjs();
        for (Exchange::FITKAcousticsVTKGraphObject3D* addinObj : addinObjs)
        {
            if (!addinObj)
            {
                continue;
            }

            addinObj->removeFromGraphWidget();
            graphWidget->addObject(addinObj->getRenderLayer(), addinObj, true);
            addinObj->setFITKRender(graphWidget->getRenderer(addinObj->getRenderLayer()));
        }
        //}

        // 刷新窗口。
        //@{
        if (fitView)
        {
            graphWidget->fitView();
        }
        else
        {
            graphWidget->reRender();
        }
        //@}
    }

    void OperGraphEvent3D::fastAddGraphObjectToWidget(Exchange::FITKAcousticsVTKGraphObject3D* obj, Comp::FITKGraph3DWindowVTK* graphWidget)
    {
        // 添加可视化对象。
        //@{
        obj->removeFromGraphWidget();
        graphWidget->fastAddObject(obj->getRenderLayer(), obj);
        obj->setFITKRender(graphWidget->getRenderer(obj->getRenderLayer()));
        //}

        // 添加附加可视化对象。
        //@{
        QList<Exchange::FITKAcousticsVTKGraphObject3D*> addinObjs = obj->getAddinGraphObjs();
        for (Exchange::FITKAcousticsVTKGraphObject3D* addinObj : addinObjs)
        {
            if (!addinObj)
            {
                continue;
            }

            addinObj->removeFromGraphWidget();
            graphWidget->fastAddObject(addinObj->getRenderLayer(), addinObj);
            addinObj->setFITKRender(graphWidget->getRenderer(addinObj->getRenderLayer()));
        }
        //}
    }

    QList<Exchange::FITKAcousticsVTKGraphObject3D*> OperGraphEvent3D::getGraphObjectsByDataId(int dataObjId, bool forceUpdate)
    {
        // 获取或创建可视化对象。
        Exchange::FITKAcousticsVTKGraphObject3D* obj{ nullptr };
        QList<Exchange::FITKAcousticsVTKGraphObject3D*> objs;
        bool isValid = false;

        // 获取当前拾取模式，激活拾取状态。
        GUI::GUIPickInfoStru pickInfo = GUI::GUIPickInfo::GetPickInfo();
        GUI::GUIPickInfo::PickObjType pickObjType = pickInfo._pickObjType;

        // 获取可视化窗口。
        Comp::FITKGraph3DWindowVTK* graphWidget = getPreGraphWidget();
        if (!graphWidget)
        {
            return objs;
        }

        // 获取数据对象。
        Core::FITKAbstractDataObject* dataObj = Core::FITKDataRepo::getInstance()->getDataByID(dataObjId);
        if (!dataObj)
        {
            return objs;
        }

        // 获取模型与符号可视化对象管理器。
        GraphData::GraphModelProvider* modelProvider = GraphData::GraphProviderManager::getInstance()->getModelProvider(graphWidget);
        GraphData::GraphMarkProvider* markProvider = GraphData::GraphProviderManager::getInstance()->getMarkProvider(graphWidget);      
        if (!modelProvider || !markProvider)
        {
            return objs;
        }

        // 检查数据ID是否为几何模型（命令）。
        Interface::FITKAbsGeoCommand* geoCmd = dynamic_cast<Interface::FITKAbsGeoCommand*>(dataObj);
        if (geoCmd && !isValid)
        {
            obj = modelProvider->getModelGraphObject(dataObjId);
            isValid = true;

            // 判断拾取模式是否为几何拾取。
            if (obj)
            {
                switch (pickObjType)
                {
                case GUI::GUIPickInfo::POBJGeometryVert:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickVertex);
                    break;
                case GUI::GUIPickInfo::POBJGeometryEdge:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickEdge);
                    break;
                case GUI::GUIPickInfo::POBJGeometryFace:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickFace);
                    break;
                case GUI::GUIPickInfo::POBJGeometrySolid:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickSolid);
                    break;
                default:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickNone);
                    break;
                }
            }
        }

        // 检查数据ID是否为网格部件。
        AbaqusData::FITKAbaqusPart* partMesh = dynamic_cast<AbaqusData::FITKAbaqusPart*>(dataObj);
        if (partMesh && !isValid)
        {
            obj = modelProvider->getMeshGraphObject(dataObjId);
            isValid = true;

            // 判断拾取模式是否为网格拾取。
            if (obj)
            {
                switch (pickObjType)
                {
                case GUI::GUIPickInfo::POBJMeshCell:
                case GUI::GUIPickInfo::POBJMeshCell1D:
                case GUI::GUIPickInfo::POBJMeshCell2D:
                case GUI::GUIPickInfo::POBJMeshCell3D:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickElement);
                    break;
                default:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickNone);
                    break;
                }
            }
        }

        // 检查数据ID是否为SEA子系统。
        Acoustics::FITKAbstractSEASubSys* subSys = dynamic_cast<Acoustics::FITKAbstractSEASubSys*>(dataObj);
        if (subSys && !isValid)
        {
            obj = modelProvider->getSEASubSysGraphObject(dataObjId, forceUpdate);
            isValid = true;

            // 判断拾取模式是否关闭。
            if (obj)
            {
                switch (pickObjType)
                {
                case GUI::GUIPickInfo::POBJNone:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickAll);
                    break;
                default:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickNone);
                    break;
                }
            }
        }

        // 检查数据ID是否为连接关系。
        Acoustics::FITKAbstractJunction* junction = dynamic_cast<Acoustics::FITKAbstractJunction*>(dataObj);
        if (junction && !isValid)
        {
            obj = markProvider->getJunctionGraphObject(dataObjId, forceUpdate);
            isValid = true;

            // 判断拾取模式是否为连接关系拾取。
            if (obj)
            {
                switch (pickObjType)
                {
                case GUI::GUIPickInfo::POBJNone:
                case GUI::GUIPickInfo::POBJSEAJunctions:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickAll);
                    break;
                default:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickNone);
                    break;
                }
            }
        }

        // 检查数据ID是否为载荷。
        Acoustics::FITKAcousticsAbstractLoad* loadConn = dynamic_cast<Acoustics::FITKAcousticsAbstractLoad*>(dataObj);
        if (loadConn && !isValid)
        {
            obj = markProvider->getLoadGraphObject(dataObjId);
            isValid = true;

            // 判断拾取模式是否关闭。
            if (obj)
            {
                switch (pickObjType)
                {
                case GUI::GUIPickInfo::POBJNone:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickAll);
                    break;
                default:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickNone);
                    break;
                }
            }
        }

        //检查数据ID是否是FE面
        Acoustics::FITKAcousticsFEFace* feFace = dynamic_cast<Acoustics::FITKAcousticsFEFace*>(dataObj);
        if (feFace && !isValid) {
            obj = modelProvider->getFEFaceGraphObject(dataObjId, forceUpdate);
            isValid = true;

            // 判断拾取模式是否关闭。
            if (obj)
            {
                switch (pickObjType)
                {
                case GUI::GUIPickInfo::POBJNone:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickAll);
                    break;
                default:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickNone);
                    break;
                }
            }
        }

        //检查数据ID是否是FE结构子系统
        Acoustics::FITKFESubSysStructure* feStructure = dynamic_cast<Acoustics::FITKFESubSysStructure*>(dataObj);
        if (feStructure && !isValid) {
            if (feStructure->getElementDim() == 1) {
                obj = modelProvider->getFEBeamGraphObject(dataObjId, forceUpdate);
            }
            else if(feStructure->getElementDim() == 2) {
                obj = modelProvider->getFEShellGraphObject(dataObjId, forceUpdate);
            }
            isValid = true;

            // 判断拾取模式是否关闭。
            if (obj)
            {
                switch (pickObjType)
                {
                case GUI::GUIPickInfo::POBJNone:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickAll);
                    break;
                default:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickNone);
                    break;
                }
            }
        }

        //检查数据ID是否是FE声腔子系统
        Acoustics::FITKFESubSysAcoustic* feAcoustic = dynamic_cast<Acoustics::FITKFESubSysAcoustic*>(dataObj);
        if (feAcoustic && !isValid) {
            obj = modelProvider->getFEAcousticGraphObject(dataObjId, forceUpdate);
            isValid = true;

            // 判断拾取模式是否关闭。
            if (obj)
            {
                switch (pickObjType)
                {
                case GUI::GUIPickInfo::POBJNone:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickAll);
                    break;
                default:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickNone);
                    break;
                }
            }
        }

        //检查数据ID是否是FE传感器
        Acoustics::FITKAcousticsSensors* feSensors = dynamic_cast<Acoustics::FITKAcousticsSensors*>(dataObj);
        if (feSensors && !isValid) {
            obj = modelProvider->getSensorGraphObject(dataObjId);
            isValid = true;

            // 判断拾取模式是否关闭。
            if (obj)
            {
                switch (pickObjType)
                {
                case GUI::GUIPickInfo::POBJNone:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickAll);
                    break;
                default:
                    obj->setPickMode(Exchange::FITKAcousticsVTKCommons::ShapePickMode::PickNone);
                    break;
                }
            }
        }

        // 暂不支持通过该接口获取SEA节点可视化对象。
        if (obj){
            objs.push_back(obj);
        }

        return objs;
    }

    void OperGraphEvent3D::saveRuntimeSettings(QString key, QVariant value)
    {
        // 保存配置。
        AppFrame::FITKRunTimeSetting* rtSettings = FITKAPP->getGlobalData()->getRunTimeSetting();
        if (rtSettings)
        {
            rtSettings->setValue(key, value);
        }
    }

    void OperGraphEvent3D::reRender()
    {
        for (Comp::FITKGraph3DWindowVTK* graphWidget : getAllGraphWidget()) {
            if (graphWidget == nullptr) {
                continue;
            }
            graphWidget->reRender();
        }
    }

    void OperGraphEvent3D::fitView()
    {
        for (Comp::FITKGraph3DWindowVTK* graphWidget : getAllGraphWidget()) {
            if (graphWidget == nullptr) {
                continue;
            }
            graphWidget->fitView();
        }
    }
}  // namespace GUIOper